#include "encode.hpp"

// encode message with generator matrix G.
inline void encode(vec_GF2& codeword, const vec_GF2& msg, const mat_GF2& G){
  codeword = msg * G;
}

// generate a random codeword
void generate_random_codeword(vec_GF2& codeword, const mat_GF2& G){
  codeword.SetLength(N);
  srand(time(NULL));
  encode(codeword, random_vec_GF2(K), G);
}

// verify the correctness of the generator matrix G
void verify_G(const mat_GF2& G, const mat_GF2& H){
  vec_GF2 codeword;
  generate_random_codeword(codeword, G);
  vec_GF2 x = H * codeword;
  if (IsZero(x)){
#ifdef VERBOSE
    cout << "passed verification" << endl;
#endif
  }
  else{
    cout << "bug in G matrix gengeration" << endl;
    cout << x << endl;
  }
}


// for preventing the seed to be the same for each gsl
time_t gsl_seed = time(NULL) * rand();

// construct one random number generator
gsl_rng* get_one_rand_num_generator() {
  const gsl_rng_type * T;
  gsl_rng * r;
  /* create a generator chosen by the 
     environment variable GSL_RNG_TYPE */
  gsl_rng_env_setup();
  gsl_rng_default_seed =  gsl_seed;
  gsl_seed += rand(); // ok for PC, not for HPC: time(NULL) + N * clock() % K;
  sleep(0.2);
#ifdef VERBOSE
  cout << "seed of gsl:" << gsl_rng_default_seed << endl;
#endif
  T = gsl_rng_default;
  r = gsl_rng_alloc (T);
  return r;
}

// add the noise simulating BSC
void add_noise_bsc(vec_GF2& codeword){
  const double P[2] = {(1 - fliprate), fliprate};
  gsl_ran_discrete_t* x = gsl_ran_discrete_preproc(2, P);
  gsl_rng* g = get_one_rand_num_generator();
  gsl_ran_discrete(g, x);
  for(int i = 1; i <= N; i++){
    if (gsl_ran_discrete(g, x) == 1)
      codeword(i) += 1;
  }
  delete g;
  gsl_ran_discrete_free(x);
}

// generate random noisy codeword
void generate_random_noisy_codeword(vec_GF2& original, vec_GF2& codeword, const mat_GF2& G){
  generate_random_codeword(codeword, G);
  original = codeword;
  
#ifdef DEBUG
    cout << "The original codeword" << endl;
    vec_GF2 codeword2 = codeword;
    cout << codeword2 << endl;
#endif

  add_noise_bsc(codeword);  

#ifdef DEBUG
    cout << "Noise vector:" << endl;
    cout << codeword2 - codeword << endl;
#endif
}


